# coding=utf-8

import os
from typing import List
from generator.cpp.file_type import CHeader
from generator.cpp.types import CStruct
from parse.sdb_parser import ECU
try:
    import CppHeaderParser
except :
    os.system('pip3 install robotpy-cppheaderparser')
    import CppHeaderParser

def getCurrentECUStruct(ecuName: str, ecuFileName:str, structName:str):
    currentStructFields = []
    headerFile = "../transfer/libapvp/include/vp/"+ecuFileName+".h"
    ecuHeader = CppHeaderParser.CppHeader(headerFile)
    ecuStruct = ecuHeader.classes.get(structName,None)
    if ecuStruct != None:
        for item in ecuStruct["properties"]["public"] : 
            currentStructFields.append(item["name"])
    return currentStructFields

def initStructFileds(ecuSignals:List, struct:CStruct, ecuName: str, ecuFileName:str, structName:str):
    currentStructFields = getCurrentECUStruct(ecuName, ecuFileName, structName)
    ecuFiledsDict = {}
    isTx = (ecuFileName.find("_TX") != -1)
    for signal in ecuSignals:
        key = signal.getVariableName(True,len(ecuSignals) == 1) if isTx else signal.getVariableName()
        ecuFiledsDict[key] = signal.getValueType().name
    
    #将原有信号按头文件顺序添加到struct
    for field in currentStructFields : 
        if field in ecuFiledsDict :
            struct.property("{type} {name}".format(type=ecuFiledsDict[field], name=field))
            del ecuFiledsDict[field]
    #将剩余信号添加到struct
    for (field, fieldType) in ecuFiledsDict.items() :
        struct.property("{type} {name}".format(type=fieldType, name=field))

def generateECUHeadFile(ecus: List[ECU],outDir:str):
    """
    创建ecu的opid定义
    创建该ecu的每个信号值的结构体定义
    """
    for ecu in ecus:
        # 创建ecu的tx信号文件
        if ecu.hasWriteSignals():
            tx_header = CHeader(ecu.name+"_TX")
            for group in sorted(ecu.txSignals, key=lambda group: group.opcode):
                tx_header.define("{0}OpID ({1})".format(
                    group.name, hex(group.opcode)))
                txStruct = CStruct("_Op{0}_SetRequestNoReturn".format(
                    group.name), True, memory=1)
                #根据现有头文件中结构体定义，重新生成时保持原来字段的顺序
                initStructFileds(group.signals, txStruct, ecu.name.upper(), 
                                                    tx_header.file_name.upper(),
                                                    "Op{0}_SetRequestNoReturn".format(group.name.upper()))
                tx_header.addMember(txStruct)
            tx_header.toFile(os.path.join(outDir,"include/vp"),
                             tx_header.file_name.upper()+".h")
        else:
            print("{0} no tx signals".format(ecu.name))

        # 创建ecu的rx信号文件
        if ecu.hasReadSignals():
            rx_header = CHeader(ecu.name+"_RX")
            rx_header.define("{0}NotificationOpID {1}".format(
                ecu.name.upper(), hex(ecu.rxPackage.opcode)))
            struct = CStruct("_Op{0}_Notification".format(
                ecu.name.upper()), True, memory=1)
            #根据现有头文件中结构体定义，重新生成时保持原来字段的顺序
            initStructFileds(ecu.rxPackage.signals, struct, ecu.name.upper(), 
                                                rx_header.file_name.upper(),
                                                "Op{0}_Notification".format(ecu.name.upper()))

            rx_header.addMember(struct)
            rx_header.toFile(os.path.join(outDir,"include/vp"),
                             rx_header.file_name.upper()+".h")
        else:
            print("{0} no rx signals".format(ecu.name))
